package com.kl.util;

import org.junit.Test;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Base64;

/**
 * 说明：base64是一个编码算法，对数据内容进行编码以方便在网络上传输
 * 注意：虽然base64编码过后原文也变成不能看到的字符格式，但它并非安全领域下的加密解密算法
 * 适用范围：Base64特别适合在http，mime协议下快速传输数据，比如网络中图片的传输
 *
 * base64的意义：在计算机中的字节共有256个组合，对应就是ascii码，而ascii码的128～255之间的值是不可见字符；
 * 而在网络上交换数据时，比如说从A地传到B地，往往要经过多个路由设备，由于不同的设备对字符的处理方式有一些不同，
 * 这样那些不可见字符就有可能被处理错误，这是不利于传输的；
 * 所以就先把数据先做一个Base64编码，统统变成可见字符，这样出错的可能性就大降低了
 *
 * 情景需求：Base64编码是从二进制值到某些特定字符的编码，这些特定字符一共64个，所以称作Base64
 * 为什么不直接传输二进制呢？比如图片，或者字符，既然实际传输时它们都是二进制字节流；
 * 而且即使Base64编码过的字符串最终也是二进制（通常是UTF-8编码，兼容ASCII编码）在网络上传输的，
 * 那么用4/3倍带宽传输数据的Base64究竟有什么意义？
 * 真正的原因是二进制不兼容。某些二进制值，在一些硬件上，比如在不同的路由器，老电脑上，表示的意义不一样，做的处理也不一样；
 * 同样，一些老的软件，网络协议也有类似的问题，但是万幸，
 * Base64使用的64个字符，经ASCII/UTF-8编码后在大多数机器，软件上的行为是一样的
 *
 * 总结：Base64是为二进制数据编码解码的工具
 */
public class Base64Test {
    /**
     * Base64
     */
    public static void base64Demo(String str) {
        byte[] bytes = str.getBytes();
        //Base64 加密
        String encoded = Base64.getEncoder().encodeToString(bytes);
        System.out.println("Base 64 编码后：" + encoded);

        //Base64 解密
        byte[] decoded = Base64.getDecoder().decode(encoded);
        String decodeStr = new String(decoded);
        System.out.println("Base 64 解码后：" + decodeStr);
        System.out.println();
    }

    /**
     * BASE64编码解码
     */
    public static void enAndDeCodeDemo(String str) throws Exception {
        String data = encryptBASE64(str.getBytes());
        System.out.println("sun.misc.BASE64 加密后：" + data);

        byte[] byteArray = decryptBASE64(data);
        System.out.println("sun.misc.BASE64 解密后：" + new String(byteArray));
    }

    /**
     * BASE64解码
     */
    public static byte[] decryptBASE64(String key) throws Exception {
        return (new BASE64Decoder()).decodeBuffer(key);
    }

    /**
     * BASE64编码
     */
    public static String encryptBASE64(byte[] key) {
        return (new BASE64Encoder()).encodeBuffer(key);
    }

    @Test
    public void test1() throws Exception {
        String str = "青龙偃月刀";
        // 第一种base64编解码
        base64Demo(str);
        // 第二种base64编解码
        enAndDeCodeDemo(str);
    }

    /***
     * 编码文件
     * @param path 文件路径
     */
    public static String encodeBase64File(String path) throws Exception {
        File file = new File(path);
        FileInputStream inputFile = new FileInputStream(file);
        byte[] buffer = new byte[(int) file.length()];
        inputFile.read(buffer);
        inputFile.close();
        return new sun.misc.BASE64Encoder().encode(buffer);
    }

    /***
     * 解码文件并保存
     */
    public static void decoderBase64File(String base64Code, String targetPath)
            throws Exception {
        byte[] buffer = new sun.misc.BASE64Decoder().decodeBuffer(base64Code);
        FileOutputStream out = new FileOutputStream(targetPath);
        out.write(buffer);
        out.close();

    }

    /***
     * 将编码后的数据保存到指定路径下的文件
     */
    public static void toFile(String base64Code, String targetPath) throws Exception {
        byte[] buffer = base64Code.getBytes();
        FileOutputStream out = new FileOutputStream(targetPath);
        out.write(buffer);
        out.close();
    }

    @Test
    public void test2() throws Exception {
        String base64File = encodeBase64File("src/main/java/com/kl/util/images.jpeg");
        System.out.println("编码后的图片 = " + base64File);
        // 保存编码内容
        toFile(base64File, "src/main/java/com/kl/util/temp.txt");
        // 解码图片并保存
        decoderBase64File(base64File, "src/main/java/com/kl/util/decodeImg.jpeg");
    }
}